# -*- coding: utf-8 -*-
import json
import re
import threading
import time
from typing import List

from langchain_core.prompts import PromptTemplate

from logs import logger
from pdf_resovle import pdf_util
from vector import remote_milvus
from embedding import demo
from glm import glm_model
from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED, FIRST_COMPLETED
from vector import remote_milvus


def notice_index(pdf_file):
    """
    对pdf文件进行解析,并建立索引
    :param pdf_file:
    :return:
    """
    logger.info('notice_index start...')
    # 1.解析pdf文件,获取[(title,body)]
    title_body_list, project_name, project_no = pdf_util.get_data_from_pdf(pdf_file)
    # 2.将[(title,body)]转化为可以入库的datas
    datas = generate_import_datas(title_body_list, project_name, project_no)
    # 3.如果向量库中对应的project_no已经存在，则先删除所有的数据
    if remote_milvus.has_entity("notice", project_no):
        remote_milvus.del_entities("notice", project_no)
    # 4.将datas入向量库
    if datas:
        remote_milvus.import_data(datas)
    logger.info('notice_index done...')
    return project_name, project_no


def self_insert_with_qas():
    """
    手动使用qa_list进行插入
    :return:
    """
    qa_list = [('招标条件', '本招标项目梨树县2025年高标准农田建设储备项目勘察设计（第二批）已由四农局函〔2024〕41号\n文件批准建设，招标人为梨树县高标准农田建设项目领导小组办公室，资金来源为财政资金，项目出资比\n例100%，项目已具备招标条件，现对该项目勘察设计（第二批）1标段进行公开招标。'), ('项目概况与招标内容', "2.1项目名称：梨树县2025年高标准农田建设储备项目勘察设计（第二批）1标段\n2.2标段划分及招标内容：\n[['序号', '标段名称', '建设地点', '主要内容', '最高投标限价'], ['1', '梨树县2025年高标准农田建\\n设储备项目勘察设计（第二批）\\n1标段', '梨树县各乡镇', '1、可行性研究报告\\n2、初步设计报告\\n3、设计变更报告\\n4、项目上图入库', '费率不超过总投\\n资额的2%']]\n2.3服务期限：接到业主通知后45日内完成初步设计（具体根据业主要求）；整个服务期限自设计合\n同签订之日起至本工程竣工、验收、结算完毕为止（招标人对每个项目设计的工期如有不同要求，可在具\n体合同中协商明确）。\n2.4质量要求：符合《高标准基本农田建设规范（试行）》《高标准基本农田建设标准》（TD/T1033-2012）、\n《高标准农田建设通则》（GB/T30600-2022）及国家、吉林省关于高标准农田建设的其他基本要求的合格\n标准。"), ('投标人资格要求', '3.1本次招标初步设计文件应由具有相应勘察、设计资质且信用状况良好的机构进行编制，并达到规\n定的深度。测绘应具有国家测绘地理信息局核发的测绘乙级及以上资质；勘察设计应同时具有岩土工程勘\n察专业类丙级及以上资质和水利工程设计专业资质乙级及以上资质；\n3.2项目负责人要求具备相关专业高级工程师职称证书；\n3.3投标人须在投标文件里提供投标人代表和项目组成人员（不含退休人员）开标前一个月内以投标\n人名义缴纳的，正常缴费状态的个人参保证明，证明上的二维码要保证移动终端可以扫描识别验证真伪，\n如该投标人所在的地区确实没有带二维码的证明，须提供网上查询方式，否则投标无效；\n3.4投标人须在投标文件里提供投标文件递交截止日前一年内任一月份的缴税凭证或完税证明等复印\n件，依法免税的，应提供相应资料（复印件）证明其依法免税；\n3.5投标申请人须提供近三年（2021年-2023年）经会计师事务所审计的财务审计报告。（当投标单\n位成立日期在2021年-2023年之间的，提供从成立日期起至2023年之间的经会计师事务所审计的财务审\n计报告，2024年1月1日以后新成立的公司无财务审计报告的，需提供一份财务状况良好承诺）；\n3.6外省入吉建筑业企业应按照要求办理入吉建筑业企业信息登记；\n3.7拒绝列入政府取消投标资格记录期间的企业或个人投标；\n3.8投标人未在国家企业信用信息公示系统（www.gsxt.gov.cn）中列入严重违法失信名单（黑名单）\n信息，投标人在“信用中国”网站（www.creditchina.gov.cn）无任何不良信用记录；在近三年（2021年\n1月1日至今）投标人或其法定代表人、拟委派的项目负责人未在“中国裁判文书网”(wenshu.court.gov.cn)\n上有行贿犯罪行为；\n3.9与招标人存在利害关系可能影响招标公正性的法人、其他组织或者个人，不得参加投标。单位负\n责人为同一人或者存在控股、管理关系的不同单位，不得参加同一标段投标或者未划分标段的同一招标项\n目投标。违反这两款规定的，相关投标均无效；\n为招标项目提供整体设计、规范编制或者项目管理、监理、检测等服务的投标人，不得再参加本招标\n项目的其他招标活动；\n3.10本项目不接受联合体投标。'), ('招标文件的获取', '4.1凡有意参加投标者，请于2024年09月24日至2024年09月29日，在吉林省公共资源交易一体\n化平台（https://www.ggzyyth.jl.cn/EpointSSO/memberLogin）网站下载招标文件。\n4.2下载招标文件须办理一体化平台CA，如有疑问请拨打咨询服务电话：0434-3211113，0434-3211119。\n4.3本项目招标文件的质疑、澄清、修改、补充等内容在吉林省公共资源交易一体化平台\n（https://www.ggzyyth.jl.cn/EpointSSO/memberLogin）网站上发布信息向所有投标人公布。\n4.4招标文件的澄清文件、答疑文件、补遗文件一经发布即视为已告知了所有投标人，且投标人也已\n经收到并明确了该文件的内容。投标人须主动阅知，以免错过信息影响投标。\n4.5 有效投标人不足三家时，招标人另行组织招标。'), ('投标文件的递交', '5.1投标文件递交的截止时间（投标截止时间，下同）：2024年10月14日09:30时，地点为四平\n市公共资源交易中心（四平市铁西区北建平街1号）2楼开标室；投标人应在投标文件递交截止时间前通\n过吉林省公共资源交易一体化平台系统（https://www.ggzyyth.jl.cn/EpointSSO/memberLogin）上传电\n子投标文件。逾期上传的电子投标文件，电子招标投标交易平台将予以拒收。在递交投标文件时，应按\n照有关规定提供相应数额的投标保证金。\n5.2开标形式及投标文件解密：本项目采取网上招标、网上投标、网上评标；本次开标会议将通过视\n频直播的形式进行，投标人未参加视频开标会议的，或未完全参加视频开标会议全过程的，视为认同开\n标会议结果。本项目投标文件的解密将采用远程解密的方式；开标前，投标人应在准备解密的电脑端提\n前安装好CA驱动并且能正常登录系统。开标时，等待代理机构工作人员公布投标人名单后，选择对应的\n项 目 ， 投 标 人 持 投 标 单 位 企 业 CA 锁 登 录 吉 林 省 公 共 资 源 交 易 一 体 化 平 台 系 统\n（https://www.ggzyyth.jl.cn/EpointSSO/memberLogin），进入“远程开标解密”菜单，按照开标会议\n主持人的指令，选择对应的项目的投标文件进行远程解密（开标前及开评标系统公布投标人名单前，不\n要提前进行远程解密），点击远程解密并输入CA密码，成功解密后状态会显示“已解密”。投标文件解\n密时需插上生成投标文件的CA锁进行解密，且正确输入密码，投标人未在规定的时间内成功解密或因投\n标人自身原因未能成功解密的，投标无效；投标人由于数字证书遗失、损坏、更换、续期等情况导致投\n标文件无法解密的，由投标人自行承担责任。现场参加开标人员：招标人代表、招标代理机构项目负责\n人、行业监管部门代表。投标人可在网上同步收看开标直播，直至开标结束。'), ('发布公告的媒介', '本次招标公告同时在《吉林省公共资源交易一体化平台系统\n（https://www.ggzyyth.jl.cn/EpointSSO/memberLogin）》《中国招标投标公共服务平台》上发布。'), ('联系方式', '招标人：梨树县高标准农田建设项目领导小组办公室\n地 址：梨树县梨树镇树文街25号\n联系人：顾明\n联系电话：0434-5288177\n招标代理机构：吉林省嘉丰项目管理有限公司\n地 址：四平市铁西区\n联系人：郭磊\n联系方式：0434-3281189\n监督管理部门：四平市农业农村局'), ('招标项目的名称是什么？', "['梨树县2025年高标准农田建设储备项目勘察设计（第二批）']"), ('招标项目的批准文件编号是什么？', "['四农局函〔2024〕41号']"), ('招标项目的批准机构是什么？', "['四农局']"), ('招标人是谁？', "['梨树县高标准农田建设项目领导小组办公室']"), ('招标项目的资金来源是什么？', "['财政资金']"), ('项目出资比例是多少？', "['100%']"), ('招标项目是否已具备招标条件？', "['是']"), ('本次招标针对的是哪个标段？', "['勘察设计（第二批）1标段']"), ('本次招标的类型是什么？', "['公开招标']"), ('项目名称是什么？', "['梨树县2025年高标准农田建设储备项目勘察设计（第二批）1标段']"), ('标段划分及招标内容有哪些？', "['序号: 1', '标段名称: 梨树县2025年高标准农田建设储备项目勘察设计（第二批）1标段', '建设地点: 梨树县各乡镇', '主要内容: 1、可行性研究报告；2、初步设计报告；3、设计变更报告；4、项目上图入库', '最高投标限价: 费率不超过总投额的2%']"), ('服务期限是多久？', "['接到业主通知后45日内完成初步设计；整个服务期限自设计合同签订之日起至本工程竣工、验收、结算完毕为止']"), ('质量要求符合哪些标准？', "['《高标准基本农田建设规范（试行）》', '《高标准基本农田建设标准》（TD/T1033-2012）', '《高标准农田建设通则》（GB/T30600-2022）', '国家关于高标准农田建设的其他基本要求', '吉林省关于高标准农田建设的其他基本要求']"), ('本次招标的初步设计文件应由哪些机构进行编制？', "['具有相应勘察、设计资质且信用状况良好的机构']"), ('测绘资质应达到什么级别？', "['测绘乙级及以上资质']"), ('勘察设计应具备哪些资质？', "['岩土工程勘察专业类丙级及以上资质', '水利工程设计专业资质乙级及以上资质']"), ('项目负责人需要具备什么职称？', "['相关专业高级工程师职称证书']"), ('投标人需要提供哪些人员的个人参保证明？', "['投标人代表和项目组成人员（不含退休人员）']"), ('个人参保证明需要满足什么条件？', "['开标前一个月内以投标人名义缴纳', '正常缴费状态', '二维码可扫描验证']"), ('若当地证明无二维码，投标人需要提供什么？', "['网上查询方式']"), ('投标文件中应提供什么缴税证明？', "['投标文件递交截止日前一年内任一月份的缴税凭证或完税证明']"), ('依法免税的投标人需要提供什么证明？', "['相应资料（复印件）证明其依法免税']"), ('投标申请人需要提供多长时间的财务审计报告？', "['近三年（2021年-2023年）']"), ('新成立的公司需要提供什么？', "['财务状况良好承诺']"), ('外省入吉建筑业企业需要办理什么登记？', "['入吉建筑业企业信息登记']"), ('哪些企业或个人不得参加投标？', "['列入政府取消投标资格记录期间的企业或个人']"), ('投标人需要在哪些网站上没有不良记录？', "['国家企业信用信息公示系统', '信用中国', '中国裁判文书网']"), ('哪些与招标人有利害关系的单位或个人不得参加投标？', "['存在控股、管理关系的不同单位', '为招标项目提供整体设计、规范编制或者项目管理、监理、检测等服务的投标人']"), ('本项目是否接受联合体投标？', "['不接受']"), ('投标者应在什么时间范围内下载招标文件？', "['2024年09月24日至2024年09月29日']"), ('招标文件应该在哪个平台下载？', "['吉林省公共资源交易一体化平台（https://www.ggzyyth.jl.cn/EpointSSO/memberLogin）']"), ('下载招标文件需要办理什么？', "['一体化平台CA']"), ('遇到疑问时，应拨打哪个咨询服务电话？', "['0434-3211113，0434-3211119']"), ('招标文件的质疑、澄清、修改、补充等内容在哪里发布？', "['吉林省公共资源交易一体化平台（https://www.ggzyyth.jl.cn/EpointSSO/memberLogin）']"), ('澄清文件、答疑文件、补遗文件发布后，投标人应该如何处理？', "['主动阅知以免错过信息影响投标']"), ('有效投标人不足三家时，招标人会如何处理？', "['另行组织招标']"), ('投标文件递交的截止时间是什么时候？', "['2024年10月14日09:30时']"), ('投标文件递交的地点在哪里？', "['四平市公共资源交易中心2楼开标室（四平市铁西区北建平街1号）']"), ('投标人应通过哪个平台上传电子投标文件？', "['吉林省公共资源交易一体化平台系统（https://www.ggzyyth.jl.cn/EpointSSO/memberLogin）']"), ('逾期上传的电子投标文件会被如何处理？', "['电子招标投标交易平台将予以拒收']"), ('在递交投标文件时，投标人需要提供什么？', "['相应数额的投标保证金']"), ('开标形式是什么？', "['网上招标、网上投标、网上评标']"), ('开标会议将通过什么形式进行？', "['视频直播']"), ('投标人未参加视频开标会议会有什么后果？', "['视为认同开标会议结果']"), ('投标文件的解密方式是什么？', "['远程解密']"), ('在开标前，投标人需要做什么？', "['在准备解密的电脑端提前安装好CA驱动并且能正常登录系统']"), ('如何进行投标文件的远程解密？', "['持投标单位企业CA锁登录吉林省公共资源交易一体化平台系统，进入‘远程开标解密’菜单，按照开标会议主持人的指令进行操作']"), ('投标文件解密时需要注意什么？', "['需插上生成投标文件的CA锁进行解密，且正确输入密码']"), ('投标人未在规定时间内成功解密会有什么后果？', "['投标无效']"), ('投标文件因数字证书问题无法解密，责任由谁承担？', "['投标人自行承担责任']"), ('现场参加开标的人员有哪些？', "['招标人代表、招标代理机构项目负责人、行业监管部门代表']"), ('投标人可以如何参与开标？', "['在网上同步收看开标直播']"), ('本次招标公告在哪些平台上发布？', "['吉林省公共资源交易一体化平台系统', '中国招标投标公共服务平台']"), ('如何访问吉林省公共资源交易一体化平台系统？', "['访问地址：https://www.ggzyyth.jl.cn/EpointSSO/memberLogin']"), ('招标人的名称是什么？', "['梨树县高标准农田建设项目领导小组办公室']"), ('招标人的地址在哪里？', "['梨树县梨树镇树文街25号']"), ('招标人的联系人是谁？', "['顾明']"), ('招标人的联系电话是什么？', "['0434-5288177']"), ('招标代理机构的名称是什么？', "['吉林省嘉丰项目管理有限公司']"), ('招标代理机构的地址在哪里？', "['四平市铁西区']"), ('招标代理机构的联系人是谁？', "['郭磊']"), ('招标代理机构的联系方式是什么？', "['0434-3281189']"), ('监督管理部门是哪个？', "['四平市农业农村局']")]
    datas = generate_datas_by_qas(qa_list, "梨树县2025年高标准农田建设储备项目勘察设计（第二批）1标段", "SPS20240923NTGC01001")
    if datas:
        count = remote_milvus.import_data(datas)
    logger.info('self_insert_with_qas done...count={}',count)



def generate_datas_by_qas(qa_list, project_name, project_no):
    if not qa_list:
        return []
    # 将qa_list转为datas
    datas = []
    embedding_fn = demo.get_embedding
    # 对所有的project_name + question进行encoding
    question_vectors = embedding_fn([project_name + question for question, _ in qa_list], convert_to_numpy=False)
    for i, (question, answer) in enumerate(qa_list):
        """
            schema.add_field(field_name="project_name", datatype=DataType.VARCHAR, max_length=128)
            schema.add_field(field_name="project_no", datatype=DataType.VARCHAR, max_length=64)
            schema.add_field(field_name="question", datatype=DataType.VARCHAR, max_length=128)
            schema.add_field(field_name="question_vector", datatype=DataType.FLOAT_VECTOR, dim=768)
            schema.add_field(field_name="answer", datatype=DataType.VARCHAR, max_length=65535)
        """
        datas.append({
            "project_name": project_name,
            "project_no": project_no,
            "question": question,
            "question_vector": question_vectors[i],
            "answer": answer
        })
    return datas


def generate_import_datas(title_body_list, project_name, project_no) -> List:
    """
    将title_body_list转为可以入库的datas
    :param title_body_list:
    :param project_name:
    :param project_no:
    :return:
    """
    # 1.title_body_list转为qa问答对数据[(question,answer)]
    qa_list = generate_notice_qas(title_body_list)
    # 2.qa问答对数据拼装为datas
    return generate_datas_by_qas(qa_list, project_name, project_no)


def generate_notice_qas(title_body_list):
    # 1.直接将title作为question,body作为answer
    qas = [(title, body) for title, body in title_body_list]
    # 2.使用多线程调用llm生成question
    # for title, body in title_body_list:
    #     llm_qas = generate_qas_llm(title, body)
    #     qas.extend(llm_qas)
    llm_qas = get_llm_qas_with_threads(title_body_list)
    qas.extend(llm_qas)
    logger.info('generate_notice_qas done, qas: {}', qas)
    return qas


def generate_qas_llm(title, body):
    logger.info('generate_qas_llm start, title: {}, body: {},current_thread={}', title, body,
                threading.currentThread().getName())
    json_example = """
    ```json
    {
            "questions_answers": [
                {
                  "question": "替换成具体的问题",
                  "answer": [
                    "答案1"
                  ]
                }
            ]
        }
    ```
    """
    prompt_str = """
    如果你是一名招投标技术专家，
    将下面的文档的关键信息拆分为最小粒度的问题和答案，以json的方式输出
    ！！！严格按照下面的示例json格式进行输出:
    {json_example},
    具体文档如下:{text}
    """
    prompt = PromptTemplate.from_template(prompt_str)
    query = prompt.invoke({"json_example": str(json_example), "text": body}).to_string()
    response = glm_model.chat_llm(query)
    logger.info("glm_model.chat_llm,response:{}", response)
    return analysis_markdown_json(response)


def analysis_markdown_json(response):
    """
    解析markdown 格式的json字符串
    :param response:
    :return:
    """
    # 解析返回的json数据
    json_pattern = r"```json\n(.*?)```"
    try:
        matches = re.findall(json_pattern, response, re.DOTALL)
        if matches:
            response_json_str = matches[0]
            response_json = json.loads(response_json_str)
            return [(qa["question"], str(qa["answer"])) for qa in response_json["questions_answers"]]
    except Exception as e:
        logger.error("eval response error, response: {}, error: {}", response, e)
    return []


def get_llm_qas_with_threads(title_body_list):
    """
    多线程构造csv到data数据
    :param csv_path:csv路径
    :param embedding_func: embedding方法
    :param model_name: 模型名称
    :param collection_name: 集合名称
    :return:
    """
    start_time = time.time()
    result_datas = []
    futures = []
    with ThreadPoolExecutor(max_workers=10) as executor:
        for title, body in title_body_list:
            future = executor.submit(generate_qas_llm, title, body)
            futures.append(future)
            # 等待所有线程执行完毕
            wait(futures, return_when=ALL_COMPLETED)
    logger.info("get_llm_qas_with_threads finish futures.len={},cost_time={}", len(futures), time.time() - start_time)
    for future in futures:
        result_datas.extend(future.result())
    return result_datas


def analysis_notice_llm(query):
    logger.info('analysis_notice_llm start, query: {}', query)
    # 1. 检索向量库寻找topK context
    topK_context = remote_milvus.similarity_search(query)
    # 2. 生成prompt
    # 2.构造提示词
    prompt = PromptTemplate.from_template("""
    # 请仅根据提供的根据上下文，回答用户问题。
    你的回答必须有上下文的支持，如果上下文中没有相关信息，请回答：“暂时无法从已有知识库获取答案。”
    如果回答是多句话，使用序号标记后分条输出。
    ## 上下文：{context}
    ## 用户问题：{query}""")
    prompt_str = prompt.invoke({"query": query, "context": topK_context}).to_string()
    logger.info("analysis_notice_llm prompt_str={}", prompt_str)
    # 3. 调用llm生成答案
    result = glm_model.chat_llm(prompt_str)
    logger.info("analysis_notice_llm question={},result={}", query, result)
    return result


if __name__ == '__main__':
    # generate_qas_llm("联系方式", """
    # 招标人：梨树县高标准农田建设项目领导小组办公室
    # 地 址：梨树县梨树镇树文街25号
    # 联系人：顾明
    # 联系电话：0434-5288177
    # 招标代理机构：吉林省嘉丰项目管理有限公司
    # 地 址：四平市铁西区
    # 联系人：郭磊
    # 联系方式：0434-3281189
    # 监督管理部门：四平市农业农村局""")

    # r = analysis_markdown_json("""
    # ```json\n{\n  "questions_answers": [\n    {\n      "question": "招标人是谁？",\n      "answer": ["梨树县高标准农田建设项目领导小组办公室"]\n    },\n    {\n      "question": "招标人的地址在哪里？",\n      "answer": ["梨树县梨树镇树文街25号"]\n    },\n    {\n      "question": "招标人的联系人是谁？",\n      "answer": ["顾明"]\n    },\n    {\n      "question": "招标人的联系电话是什么？",\n      "answer": ["0434-5288177"]\n    },\n    {\n      "question": "招标代理机构是哪家公司？",\n      "answer": ["吉林省嘉丰项目管理有限公司"]\n    },\n    {\n      "question": "招标代理机构的地址在哪里？",\n      "answer": ["四平市铁西区"]\n    },\n    {\n      "question": "招标代理机构的联系人是谁？",\n      "answer": ["郭磊"]\n    },\n    {\n      "question": "招标代理机构的联系方式是什么？",\n      "answer": ["0434-3281189"]\n    },\n    {\n      "question": "监督管理部门是哪个机构？",\n      "answer": ["四平市农业农村局"]\n    }\n  ]\n}\n```
    # """)
    # print(r)
    self_insert_with_qas()
    pass
